package cn.edu.usst.cs.captcha01;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

@WebServlet(name = "helloServlet", value = "/result")
public class HelloServlet extends HttpServlet {
    public final static String CAPTCHA_ATTR = "captcha";
    public final static String CAPTCHA_LENGTH_ATTR = "captcha_length";
    public final static String SITE_ID_ATTR = "siteId";

    public final int CAPTCHA_LENGTH = 6;
    private Map<Integer, String> id_captcha_map;
    private static int id = 0;


    public void init() {
        id_captcha_map = new HashMap<>();
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        response.setCharacterEncoding("UTF-8");
        request.setCharacterEncoding("UTF-8");
        char[] code_buf = new char[CAPTCHA_LENGTH];
        for (int i = 0; i < code_buf.length; i++) {
            char index=String.valueOf(i).charAt(0);
            char temp=(char) ('0' + (int) (Math.random() * 10));
            String CAPTCHAPicAttr=getCaptchaPicAttr(index);
            String CAPTCHAPicDir=getCaptchaPicPath(temp);
            request.getSession().setAttribute(CAPTCHAPicAttr, CAPTCHAPicDir);
            code_buf[i] = temp;
        }
        request.getSession().setAttribute(CAPTCHA_LENGTH_ATTR, CAPTCHA_LENGTH);
        request.getSession().setAttribute(SITE_ID_ATTR, generateID(new String(code_buf)));

        request.getRequestDispatcher("login.jsp").forward(request, response);
    }

    private synchronized int generateID(String code) {
        int id = HelloServlet.id++;
        id_captcha_map.put(id, code);
        return id;
    }

    public static String getCaptchaPicAttr(char c) {
        return String.format("Pic_%c", c);
    }

    private String getCaptchaPicPath(char c) {
        return String.format("captcha_images/%c.png", c);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("UTF-8");
        req.setCharacterEncoding("UTF-8");
        StringBuffer message_buf = new StringBuffer();
        try (Scanner scanner = new Scanner(req.getReader())) {
            while (scanner.hasNext()) {
                message_buf.append(scanner.nextLine());
            }
        }
        Map<String, String> parse_map = this.form_submit_parse(message_buf);
        show_result(resp, verify(parse_map));
    }

    @NotNull
    private Map<String, String> form_submit_parse(@NotNull CharSequence message_buf) {
        Map<String, String> response_parse_map = new HashMap<>();
        for (String pairs : (message_buf).toString().split("&")) {
            String[] pair = pairs.split("=");
            String key = pair[0];
            String value = pair[1];
            response_parse_map.put(key, value);
        }
        return response_parse_map;
    }

    private boolean verify(Map<String, String> parse_map) {
        String code, captcha;
        int id;
        try {
            code = parse_map.get(CAPTCHA_ATTR);
            id = Integer.parseInt(parse_map.get(SITE_ID_ATTR));
            captcha = id_captcha_map.get(id);
        } catch (RuntimeException exception) {
            return false;
        }
        if (code == null) return false;
        if (captcha == null) return false;
        if(!code.equals(captcha))return false;
        id_captcha_map.remove(id);
        return true;
    }

    private void show_result(HttpServletResponse response, boolean verify_successful) throws IOException {
        response.setContentType("text/html; charset=UTF-8");
        try (Writer out = response.getWriter()) {
            String response_str = verify_successful ? "验证通过 欢迎" : "验证失败 请再试一次";
            out.write(response_str);
        }
    }

    public void destroy() {
    }
}